package config

import (
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"time"

	"gopkg.in/yaml.v2"
)

// 使用者根据自己需要修改这个结构体
var C config

type config struct {
	Debug       bool   `yaml:"debug"`
	ImServer    string `yaml:"imServer"`
	WxCorpId    string `yaml:"wxCorpId"`
	LoginServer string `yaml:"loginServer"`
	Service     struct {
		Name    string `yaml:"name"`
		Port    string `yaml:"port"`
		Version string `yaml:"version"`
	}
	Session struct {
		SessionSecret string `yaml:"sessionSecret"`
	}
	Jwt struct {
		SignKey string        `yaml:"signKey"`
		TimeOut time.Duration `yaml:"timeOut"`
	} `yaml:"jwt"`

	Pgsql struct {
		Address  string `yaml:"address"`
		Port     string `yaml:"port"`
		UserName string `yaml:"username"`
		Password string `yaml:"password"`
		DbName   string `yaml:"db_name"`
		Schema   string `yaml:"schema"`
	} `yaml:"pgsql"`

	SqlServer struct {
		Address  string `yaml:"address"`
		Port     int    `yaml:"port"`
		UserName string `yaml:"username"`
		Password string `yaml:"password"`
		DbName   string `yaml:"db_name"`
	} `yaml:"sqlServer"`
	Mysql struct {
		Address  string `yaml:"address"`
		Port     int    `yaml:"port"`
		UserName string `yaml:"username"`
		Password string `yaml:"password"`
		DbName   string `yaml:"db_name"`
	} `yaml:"mysql"`
	Redis struct {
		Key  string `yaml:"key"`
		Host string `yaml:"host"`
		Port string `yaml:"port"`
		Auth string `yaml:"auth"`
		Db   int    `yaml:"db"`
	} `yaml:"redis"`

	Sentry string `yaml:"sentry"`
	Etcd   string `yaml:"etcd"`
	Jaeger string `yaml:"jaeger"`

	Nsq struct {
		Address     string `yaml:"address"`
		Lookup      string `yaml:"lookup"`
		MaxInFlight int    `yaml:"maxInFlight"`
	} `yaml:"nsq"`

	Oss struct {
		AccessKeyId     string `yaml:"AccessKeyId"`
		AccessKeySecret string `yaml:"AccessKeySecret"`
		PublicEndPoint  string `yaml:"PublicEndPoint"`
		EndPoint        string `yaml:"EndPoint"`
		LiveEndPoint    string `yaml:"LiveEndPoint"`
		AvatarEndPoint  string `yaml:"AvatarEndPoint"`
		PublicBucket    string `yaml:"PublicBucket"`
		AvatarBucket    string `yaml:"AvatarBucket"`
		PrivateBucket   string `yaml:"PrivateBucket"`
		UploadDir       string `yaml:"UploadDir"`
		PublicAvatorUrl string `yaml:"PublicAvatorUrl"`
	} `yaml:"oss"`
	Elastic struct {
		User     string `yaml:"user"`
		Password string `yaml:"password"`
		Host     string `yaml:"host"`
		Port     string `yaml:"port"`
	} `yaml:"elastic"`
	Sms struct {
		AccessKeyId     string        `yaml:"AccessKeyId"`
		AccessKeySecret string        `yaml:"AccessKeySecret"`
		TemplateCode    string        `yaml:"TemplateCode"`
		TemplateNotify  string        `yaml:"TemplateNotify"`
		TemplateExam    string        `yaml:"TemplateExam"`
		TimeOut         time.Duration `yaml:"timeOut"`
	} `yaml:"sms"`
	Email struct {
		Alias string `yaml:"alias"`
		Host  string `yaml:"host"`
		Pass  string `yaml:"pass"`
		Port  string `yaml:"port"`
		User  string `yaml:"user"`
	} `yaml:"email"`
	Ldap struct {
		Anonymousquery string `yaml:"anonymousquery"`
		Basedn         string `yaml:"basedn"`
		Bindpwd        string `yaml:"bindpwd"`
		Binduserdn     string `yaml:"binduserdn"`
		Host           string `yaml:"host"`
		Port           string `yaml:"port"`
		Tls            string `yaml:"tls"`
		Userfield      string `yaml:"userfield"`
	} `yaml:"ldap"`
	Script struct {
		Path string `yaml:"path"`
	} `yaml:"script"`
	SangforSyncData struct {
		AppId                     string `yaml:"appId"`
		AppSecret                 string `yaml:"appSecret"`
		ServerAddress             string `yaml:"serverAddress"`
		CreateUserPath            string `yaml:"createUserPath"`
		UpdateUserPath            string `yaml:"updateUserPath"`
		QueryUserPath             string `yaml:"queryUserPath"`
		DeleteUserPath            string `yaml:"deleteUserPath"`
		DebugUserDirectoryName    string `yaml:"debugUserDirectoryName"`
		ProdUserDirectoryName     string `yaml:"prodUserDirectoryName"`
		QueryDbLimit              int    `yaml:"queryDbLimit"`
		Retries                   int    `yaml:"retries"`
		SangforUserNotExistsCode  int    `yaml:"sangforUserNotExistsCode"`
		SangforUserNotExistsCode2 int    `yaml:"sangforUserNotExistsCode2"`
	} `yaml:"sangforSyncData"`
	OpenSearchIndustry struct {
		Endpoint        string `yaml:"endpoint"`
		AccessKeyId     string `yaml:"accessKey_id"`
		AccessKeySecret string `yaml:"accessKey_secret"`
	} `yaml:"openSearch_industry"`
	Ocr struct {
		ModelId int64 `yaml:"modelId"`
	} `yaml:"modelId"`
	System struct {
		AliyunOssCallBack string `yaml:"aliyunOssCallBack"`
		LocalCallBack     string `yaml:"localCallBack"`
		AliyunRedis       struct {
			Key  string `yaml:"key"`
			Host string `yaml:"host"`
			Port string `yaml:"port"`
			Auth string `yaml:"auth"`
			Db   int    `yaml:"db"`
		} `yaml:"aliyunRedis"`
		WorkflowCallBack string `yaml:"workflowCallBack"`
	} `yaml:"system"`
	Mms struct {
		UrlHost      string `yaml:"urlHost"`
		TokenTimeOut int64  `yaml:"tokenTimeOut"`
	} `yaml:"mms"`
	Ebs struct {
		UrlHost string `yaml:"urlHost"`
	} `yaml:"ebs"`
	EbsVideo struct {
		UrlHost string `yaml:"urlHost"`
	} `yaml:"ebsVideo"`
	Koala struct {
		UrlHost string `yaml:"urlHost"`
	} `yaml:"koala"`
	Kafka struct {
		Address        string `yaml:"address"`
		GroupID        string `yaml:"groupID"`
		OffsetsInitial int64  `yaml:"offsetsInitial"`
		Topics         string `yaml:"topics"`
		User           string `yaml:"user"`
		Password       string `yaml:"password"`
	} `yaml:"kafka"`
	Zkt struct {
		QCodeTimeOut time.Duration `yaml:"QCodeTimeOut"`
	} `yaml:"zkt"`
	Ifc struct {
		PreprocessorVersion string `yaml:"preprocessorVersion"`
	} `yaml:"ifc"`
	ECM struct {
		UrlHost         string        `yaml:"urlHost"`
		IntergrationKey string        `yaml:"intergrationKey"`
		PermanentToken  string        `yaml:"permanentToken"`
		TimeOut         time.Duration `yaml:"timeOut"`
		CallBackUrl     string        `yaml:"callBackUrl"`
	} `yaml:"ecm"`
	OSB struct {
		UrlHost  string `yaml:"urlHost"`
		ClientId string `yaml:"clientId"`
		Password string `yaml:"password"`
	} `yaml:"osb"`
}

func init() {
	InitConfigV1("./config.yaml", &C)
}

// 解密配置文件
func InitConfigV1[T any](confFile string, stru T) {
	if findConfig := ExistConfig(confFile); findConfig {
		// 解析本机的 config.yaml 文件,
		if err := ReadConfigForDecrypt[T](confFile, stru, 32); err != nil {
			panic(err.Error())
		}
		fmt.Println("配置文件：" + confFile + " 解析完成！！！！！")
	} else {
		panic("未找到配置文件！！！！")
	}
}

func InitConfig() {
	configFileName := "config.yaml"
	var findConfig bool

	_, err := os.Stat(configFileName)
	if err != nil {
		if os.IsNotExist(err) {
			configFileName = "./" + configFileName
		} else {
			panic(err)
		}
	} else {
		findConfig = true
	}
	if !findConfig {
		configFileName = "config.yaml"
		for i := 0; i < 5; i++ {
			_, err := os.Stat(configFileName)
			if err != nil {
				if os.IsNotExist(err) {
					configFileName = "../" + configFileName
				} else {
					panic(err)
				}
			} else {
				findConfig = true
				break
			}
		}
	}

	var fileName string
	if findConfig {
		fileName = configFileName
	} else {
		log.Panicf("can't find 'config.yaml' ")
		return
	}

	log.Printf("found config file: %s", fileName)

	bs, err := ioutil.ReadFile(fileName)
	if err != nil {
		log.Panicf("can't read 'config.yaml'")
		return
	}

	err = yaml.Unmarshal(bs, &C)
	if err != nil {
		log.Panicf("yaml.Unmarshal err:%v; row:%s", err, bs)
		return
	}
}
